// 数组模块

/// 改变数组的方法
/**
 * ES5前的方法：
 * pop、push、sort、splice、reverse、shift、unshift
 * ES6：
 * fill
 */

// 不改变数据的方法
/**
 * ES5：
 * slice、join、indexOf、lastIndexOf、concat、toString、toLocalString
 */

// 数组遍历
/**
 * ES5
 * forEach/filter/map/every/some/reduce/reduceRight/
 * es6
 * find/findIndex/keys/values/entries
 */

/**
 * 数组扁平化处理
 */
function flatten1(arr) {
  var result = [];
  arr.forEach((item) => {
    if (Array.isArray(item)) {
      result = result.concat(flatten1(item));
    } else {
      result.push(item);
    }
  });
  return result;
}

function flatten2(arr) {
  return arr.reduce((prev, next) => {
    return prev.concat(Array.isArray(next) ? flatten2(next) : next);
  }, []);
}

function flatten3(arr) {
  return arr.toString().split(',');
}

function flatten4(arr) {
  while (arr.some((item) => Array.isArray(item))) {
    arr = [].concat(...arr);
  }
  return arr;
}

Array.prototype.reduce = function (callbackfn, initialValue) {
  // 异常处理，和 map 类似

  if (this === null || this === undefined) {
    throw new TypeError("Cannot read property 'reduce' of null");
  }

  // 处理回调类型异常

  if (Object.prototype.toString.call(callbackfn) != '[object Function]') {
    throw new TypeError(callbackfn + ' is not a function');
  }

  let O = Object(this);

  let len = O.length >>> 0;

  let k = 0;

  let accumulator = initialValue; // reduce方法第二个参数作为累加器的初始值

  if (accumulator === undefined) {
    // 初始值不传的处理
    for (; k < len; k++) {
      if (k in O) {
        accumulator = O[k];

        k++;

        break;
      }
    }
  }

  for (; k < len; k++) {
    if (k in O) {
      // 注意 reduce 的核心累加器

      accumulator = callbackfn.call(undefined, accumulator, O[k], O);
    }
  }

  return accumulator;
};
